#include "connection.h"
#include "log.h"
#include <memory>

uv_loop_t* Dispatcher::mLoop = nullptr;
accept_handle Dispatcher::mAcceptHandler = nullptr;
connect_handle Dispatcher::mConnectHandler = nullptr;

void on_connect(uv_connect_t* conn, int status)
{
    if (status < 0) {
        ALOGE("Connect Error: %d,%s\n", status, uv_err_name(status));
        return;
    }
    // 连接上服务器之后做的一些事情
    ALOGD("in connect!!!");
    Dispatcher::mConnectHandler();
}

void on_client_connect(uv_stream_t* s, int status)
{
    if (status < 0) {
        ALOGE("New Connection error: %s/n", uv_strerror(status));
        return;
    }
    ALOGD("A client coming!!!");
    std::shared_ptr<uv_tcp_t> tcp(new uv_tcp_t);
    uv_tcp_init(s->loop, tcp.get());
    if (uv_accept(s, reinterpret_cast<uv_stream_t*>(tcp.get())) == 0) {
        Dispatcher::mAcceptHandler(tcp);
    }
}

Dispatcher::Dispatcher(Session* session)
{
    mLoop = uv_default_loop();
    if (!mLoop) {
        return;
        // Dispatcher::~Dispatcher();
    }
    mSession = session;
}

Dispatcher::~Dispatcher()
{
    if (mConn) {
        delete mConn;
    }
}

void Dispatcher::Create_Socket()
{
    mSocket = std::make_shared<uv_tcp_t>();
    uv_tcp_init(mLoop, mSocket.get());
    mSocket->data = mSession;
}

void Dispatcher::Connect(std::string ip, int port, connect_handle handle)
{
    mConnectHandler = handle;
    mConn = new uv_connect_t;
    uv_ip4_addr(ip.c_str(), port, &mDest);

    uv_tcp_connect(mConn, mSocket.get(), (sockaddr*)&mDest, on_connect);
}

void Dispatcher::Bind(std::string ip, int port)
{
    uv_ip4_addr(ip.c_str(), port, &mDest);
    uv_tcp_bind(mSocket.get(), reinterpret_cast<sockaddr*>(&mDest), 0);
    ALOGD("Binding to: %s:%d", ip.c_str(), port);
}

void Dispatcher::Listen(accept_handle handle, int n)
{
    mAcceptHandler = handle;
    int r = uv_listen(reinterpret_cast<uv_stream_t*>(mSocket.get()), n, on_client_connect);
    if (r) {
        ALOGE("Listen error: %s/n", uv_strerror(r));
        exit(-1);
    }
    ALOGD("Listenning...");
}

void Dispatcher::Loop()
{
    uv_run(mLoop, UV_RUN_DEFAULT);
}

void Dispatcher::Stop()
{
    uv_stop(mLoop);
    uv_loop_close(mLoop);
}

std::shared_ptr<uv_tcp_t> Dispatcher::GetTcpHandle()
{
    return mSocket;
}
